-module(regression).
-export([get/1]).

-include("../measure_defs.hrl").

-define(OFFSET,-1).

get_a(Values) ->
    N0 = length(Values),
    N = N0+?OFFSET,
    A11 = ((N)*(N+1)*(2*N+1)) / 6,
    A12 = ((N)*(N+1)) / 2,
    A21 = A12,
    A22 = N0,
    [[A11,A12],[A21,A22]].

get_b([], B1, B2, _) ->
    [B1, B2];
get_b([Avg|Results], B1, B2, I) ->
    get_b(Results, B1+I*Avg, B2+Avg, I+1).

get_b(Values) ->
    get_b(Values, 0, 0, 1+?OFFSET).

det([[A11, A12], [A21, A22]]) ->
    A11*A22-A12*A21.

invert0([[A11, A12], [A21, A22]]) ->
    [[A22, -A12], [-A21, A11]].

mul([[A11, A12], [A21, A22]], [B1, B2]) ->
    [A11*B1+A12*B2
    ,A21*B1+A22*B2].

get_error(_, _, []) ->
    [];
get_error(Alpha, Beta, [V|Values]) ->
    [abs(Beta-V)
    |get_error(Alpha, Beta+Alpha, Values)
    ].

get_scenario(Classes) ->
    Values = lists:map(fun (#results{avg=Avg}) -> Avg end, Classes),
    A = get_a(Values),
    B = get_b(Values),
    
    Inv0 = invert0(A),
    [Alpha0, Beta0] = mul(Inv0, B),
    Det = det(A),
    %io:format("Det= ~p~n", [Det]),
    {Alpha, Beta} = 
        if 
            abs(Det) =< 0.00001 ->
                1 = length(Values),
                {0
                ,hd(Values)
                };
            true ->
                {Alpha0/Det
                ,Beta0/Det
                }
        end,
    Errs = get_error(Alpha, Beta, Values),
    MaxErr = lists:max(Errs),
    
%     io:format("Values = ~w~n", [Values]),
%     io:format("A = ~p B=~p~n", [A, B]),
%     io:format("Det = ~p Inv0 = ~p~n", [Det, Inv0]),
%     io:format("Alpha = ~p Beta =~p~n", [Alpha, Beta]),
%     io:format("Errors = ~p~n", [Errs]),
%     io:format("MaxErr = ~p~n", [MaxErr]),
%     io:format("~n", []).
    Classes++[#tail_data{alpha = Alpha, alpha0 = Alpha/Beta, beta = Beta, reg_err = MaxErr}].

get(#all_results{res_list = Scenarios} = A) ->
    L2 =
        lists:map(
            fun (Scenario) ->
                get_scenario(Scenario)
            end, Scenarios),
    A#all_results{res_list = L2}.